package ncme.auto.framework.core.aspects;

import ncme.auto.framework.core.annotation.aspect.AutoEntityProcess;
import ncme.auto.framework.core.annotation.entity.AllowNull;
import ncme.auto.framework.core.annotation.entity.NotAllowEdit;
import ncme.auto.framework.core.annotation.entity.Pattern;
import ncme.auto.framework.core.annotation.entity.VerifyMultiRepetitionField;
import ncme.auto.framework.core.annotation.entity.VerifyRepetitionField;
import ncme.auto.framework.core.aspects.base.BaseAutoAspect;
import ncme.auto.framework.core.entities.ResMsg;
import ncme.auto.framework.core.entities.aspect.AnnotationInfo;
import ncme.auto.framework.core.entities.aspect.AspectInfo;
import ncme.auto.framework.core.entities.aspect.ParameterInfo;
import ncme.auto.framework.core.entities.aspect.RequestInfo;
import ncme.auto.framework.core.exceptions.AutoException;
import ncme.auto.framework.core.exceptions.ExceptionEnum;
import ncme.auto.framework.core.services.Impl.mian.AutoEntityServiceImpl;
import ncme.auto.framework.core.utils.StringUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;

@Aspect
@Component
public class AutoEntityProcessAspect extends BaseAutoAspect<AutoEntityProcess> {

    @Pointcut("@annotation(com.hby.common.annotation.aspect.AutoEntityProcess)")
    public void aspectCut() {
    }

    @Override
    protected void parameterPreHandler(AspectInfo aspectInfo) {
        Map<String, Object> parameter = aspectInfo.getParameter1();
        RequestInfo requestInfo = aspectInfo.getRequestInfo();
        String requestType = requestInfo.getRequestType();
        AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
        ParameterInfo parameterInfo = aspectInfo.getParameterInfo();
        AutoEntityServiceImpl<?> autoEntityServiceImpl = (AutoEntityServiceImpl<?>) aspectInfo.getBaseAutoService();
        try {
            //获取参数信息
            parameterInfo.setSearchMap(parameter);
            String[] ignoreFields = {"isDeleted", "version", "creator", "createTime", "editor", "editTime"};
            if (!requestType.equals("GET")) {  //若是GET请求，只用Map就行
                Field[] declaredFields = annotationInfo.getAutoEntityProcess().BUSINESS_ENTITY().getDeclaredFields();
                for (Field field : declaredFields) {
                    String fieldName = field.getName();
                    Object fieldValue = parameter.get(fieldName);
                    //根据字段注解将参数归类
                    for (Annotation annotation : field.getDeclaredAnnotations()) {
                        if (annotation instanceof VerifyRepetitionField) {
                            parameterInfo.addVerifyRepetitionFields(fieldName, fieldValue);
                        } else if (annotation instanceof VerifyMultiRepetitionField) {
                            parameterInfo.addVerifyMultiRepetitionFields(fieldName, fieldValue);
                        } else if (annotation instanceof AllowNull) {
                            parameterInfo.addAllowNullFields(fieldName, fieldValue);
                        } else if (annotation instanceof NotAllowEdit) {
                            parameterInfo.addNotAllowEditFields(fieldName, fieldValue);
                        } else if (annotation instanceof Pattern && fieldValue != null) {
                            parameterInfo.addPatternKeys(fieldName, new String[]{fieldValue.toString(), ((Pattern) annotation).value()});
                        }
                    }
                    //获取需要的参数值
                    if (ArrayUtils.contains(ignoreFields, fieldName)) parameter.remove(fieldName);
                    else {
                        if (parameter.containsKey(fieldName))
                            parameterInfo.addRequiredFields(fieldName, fieldValue);
                        if (requestType.equals("PUT") && !fieldName.equals("id") && parameterInfo.getNotAllowEditFields().containsKey(fieldName)) {
                            parameter.remove(fieldName);
                        }
                    }
                }
                //将map封装成业务实体对象
                parameterInfo.setBusinessEntity(autoEntityServiceImpl.createEntityFromMap(annotationInfo.getAutoEntityProcess().BUSINESS_ENTITY(), parameter));
            }
        } catch (Exception e) {
            throw new AutoException(ExceptionEnum.PARAM_FIELD, "获取参数信息失败，caused by: " + e.getMessage());
        }
    }

    @Override
    protected void parameterVerify(AspectInfo aspectInfo) {
        RequestInfo requestInfo = aspectInfo.getRequestInfo();
        AnnotationInfo annotationInfo = aspectInfo.getAnnotationInfo();
        ParameterInfo parameterInfo = aspectInfo.getParameterInfo();
        if (requestInfo.getRequestType().equals("POST") || requestInfo.getRequestType().equals("PUT")) {
            //正则验证
            Map<String, Object> patternKeys = parameterInfo.getPatternKeys();
            patternKeys.keySet().forEach(key -> {
                String[] valuePattern = (String[]) patternKeys.get(key);
                if (!java.util.regex.Pattern.matches(valuePattern[1], valuePattern[0]))
                    throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数" + key + "不符合格式要求：" + valuePattern[1]);
            });
        }
        if (!annotationInfo.getAutoEntityProcess().AUTO_EXECUTE()) return;
        switch (requestInfo.getRequestType()) {
            case "GET":
                break;
            case "POST":
                //空值验证
                for (String key : parameterInfo.getRequiredFields().keySet()) {
                    if (!parameterInfo.getAllowNullFields().containsKey(key) && (parameterInfo.getRequiredFields().get(key) == null || StringUtil.isEmpty(parameterInfo.getRequiredFields().get(key).toString())))
                        throw new AutoException(ExceptionEnum.PARAM_FIELD, "需包含参数" + key + "且不能为null或空值");
                }
                break;
            case "PUT":
                //空值验证
                for (String key : parameterInfo.getRequiredFields().keySet()) {
                    if (!parameterInfo.getAllowNullFields().containsKey(key) && parameterInfo.getRequiredFields().get(key) != null && StringUtil.isEmpty(parameterInfo.getRequiredFields().get(key).toString()))
                        throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数" + key + "不能为null或空值");
                }
                break;
            case "DELETE":
                //检查有效标识字段的数量
                int validIdentifyFieldNum = 0;
                if (parameterInfo.getId() != null) validIdentifyFieldNum += 1;
                validIdentifyFieldNum += parameterInfo.getVerifyRepetitionFields().values().stream().filter(Objects::nonNull).count();
                if (parameterInfo.getVerifyMultiRepetitionFields().size() != 0 && !parameterInfo.getVerifyMultiRepetitionFields().containsValue(null))
                    validIdentifyFieldNum += 1;
                if (validIdentifyFieldNum == 0) throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数缺少标识字段");
                else if (validIdentifyFieldNum > 1) throw new AutoException(ExceptionEnum.PARAM_FIELD, "参数含有多个标识字段");
                break;
            default:
                throw new AutoException(ExceptionEnum.PARAM_FIELD, "未知请求类型");
        }
    }

    @Override
    protected ResMsg autoProcess(AspectInfo aspectInfo) {
        parameterPreHandler(aspectInfo);
        RequestInfo requestInfo = aspectInfo.getRequestInfo();
        ParameterInfo parameterInfo = aspectInfo.getParameterInfo();
        AutoEntityServiceImpl<?> autoEntityServiceImpl = (AutoEntityServiceImpl<?>) aspectInfo.getBaseAutoService();
        switch (requestInfo.getRequestType()) {
            case "GET":
                return autoEntityServiceImpl.baseQuerySearch(parameterInfo.getSearchMap());
            case "POST":
                return autoEntityServiceImpl.baseQueryAddObj(parameterInfo.getBusinessEntity());
            case "PUT":
                return autoEntityServiceImpl.baseQueryEditObj(parameterInfo.getBusinessEntity());
            case "DELETE":
                return autoEntityServiceImpl.baseQueryDelObj(parameterInfo.getBusinessEntity());
            default:
                throw new AutoException(ExceptionEnum.PARAM_FIELD, "未知请求类型");
        }
    }

}
